home *** CD-ROM | disk | FTP | other *** search
- /*
- * Deliver to the users mailbox
- * Does most of the interesting, non-mechanical work. It tries hard
- * not to parse the message unless needed.
- *
- * Severe hacking done this file reconstructed from bits of old
- * qu2lo_send.c and a lot of new stuff.
- *
- * Julian Onions <jpo@cs.nott.ac.uk> August 1985
- */
-
- #include "util.h"
- #include "mmdf.h"
- #include "phs.h"
- #include "ap.h"
- #include "ch.h"
- #include <pwd.h>
- #include <sys/stat.h>
- #include <signal.h>
- #include <sgtty.h>
- #include "adr_queue.h"
- #include "hdr.h"
-
- extern Chan *chanptr;
- extern LLog *logptr;
-
- extern int errno;
-
- extern int sentprotect;
- extern int flgtrest;
- extern int numfds;
- extern long qu_msglen;
- extern jmp_buf timerest;
-
- extern char *strcpy();
-
- extern char *mldflfil; /* name of local mailbox file */
- extern char *mldfldir; /* name of local mailbox directory */
- extern char *delim1; /* prefix and suffix lines for */
- extern char *delim2; /* delivery mailbox/msg */
- extern char *dlvfile; /* name of user deliver control file */
- extern char *sysdlvfile; /* name of system deliver control file */
- extern char *lckdfldir; /* directory to lock in */
-
- LOCVAR int mbx_fd = -1; /* handle on recipient mailbox */
-
- extern char lo_info[]; /* type of delivery */
- extern char lo_sender[]; /* return address for message */
- extern char lo_adr[]; /* destination address from deliver */
- extern char lo_replyto[]; /* the reply address */
- extern char lo_size[];
- extern char *lo_parm; /* parameter portion of address */
- extern struct passwd *lo_pw; /* passwd struct for recipient */
-
- extern long lseek();
- extern char *strdup();
- extern char *expand();
-
- int sigpipe; /* has pipe gone bad? */
- sigtype onpipe(); /* catch that pipe write failure */
- LOCVAR char mbx_wasclear; /* this message the first in mbox? */
-
- LOCFUN lo_dofile(), qu2lo_txtcpy(), lo_pwait(), mbx_create(), mbx_close(),
- mbx_chkdelim(), hdr_line(), hdr_parse(), lookup(), setupenv();
-
- /* Structure used in lookup routines */
-
- typedef struct {
- char *l_key;
- short l_val;
- } Lookup;
-
- # define MAXLINES 200 /* max no. of lines in .maildelivery */
-
- /* the action types */
- # define M_FILE 1
- # define M_PIPE 2
- # define M_DESTROY 4
-
- /* the result types */
- # define M_ACCEPT 01
- # define M_REJECT 02
- # define M_CONDACC 03
-
- /* the special headers */
- # define M_DEFAULT 1
- # define M_TRUE 2
- # define M_ADDRESS 3
- # define M_SENDER 4
-
- typedef struct mdlvry {
- char *m_header; /* the header string */
- char *m_pattern; /* the pattern to match */
- char *m_options; /* the options string */
- unsigned short m_parse : 1; /* header type */
- unsigned short m_special : 1; /* special actions? */
- unsigned short m_hit : 1; /* have we hit */
- unsigned short m_ar : 2; /* accept reject bits */
- unsigned short m_dollar : 3; /* the dollar field */
- unsigned short m_action : 4; /* the action to do */
- unsigned short m_hdrtype : 4; /* the special hdr type */
- } Mdlvry;
-
- Lookup spec_hdrs[] = { /* the table of special headers */
- "default", M_DEFAULT,
- "true", M_TRUE,
- "addr", M_ADDRESS,
- "source", M_SENDER,
- "*", M_TRUE,
- 0, 0,
- };
-
- Lookup actions[] = { /* the table of actions */
- "pipe", M_PIPE,
- "qpipe", M_PIPE,
- "file", M_FILE,
- "destroy", M_DESTROY,
- "|", M_PIPE,
- "^", M_PIPE,
- ">", M_FILE,
- 0, 0,
- };
-
- Lookup dolfields[] = {
- "$(reply-to)", 1,
- 0, 0,
- };
-
- /*
- * Give the user something nice in the environment.
- */
- LOCVAR char *envp[] = {
- (char *) 0, /* HOME=xxx */
- (char *) 0, /* SHELL=xxx */
- (char *) 0, /* USER=xxx */
- 0
- };
-
- /*
- * Some things that can be macro expanded.
- */
- LOCVAR char *vararray[] = {
- "sender", lo_sender, /* 0/1 */
- "address", lo_adr, /* 2/3 */
- "info", lo_info, /* 4/5 */
- "reply-to", lo_replyto, /* 6/7 */
- "size", lo_size, /* 8/9 */
- 0, 0
- };
-
- /*
- * characters that need to be padded to pass to a shell
- */
-
- LOCVAR char *padchar = " \\\"'%$@#?!*|<>()&^~=+-;";
-
-
- /* */
-
- lo_slave ()
- {
- char buf[LINESIZE];
- register int result;
- Mdlvry mdlv; /* A fake construct */
- Mdlvry *mp;
-
- #ifdef DEBUG
- ll_log (logptr, LLOGBTR, "lo_slave()");
- #endif
- mp = &mdlv;
- printx ("\n");
- /* The production system of delivery attempts */
-
- /* FIRST Attempt: alias file specified file or pipe delivery */
-
- switch (*lo_parm) {
- case '|': /* send to special process */
- printx ("(sending message to piped process)\r\n\t");
- sprintf (buf, "default - | A \"%s\"", lo_parm+1);
- if( parse_line(mp, buf) != OK)
- ll_log (logptr, LLOGTMP, "problem parsing '%s'", buf);
- return ( lo_dorules(mp, mp+1) );
- case '^':
- printx ("(sending message to process unformatted)\r\n\t");
- sprintf (buf, "default - ^ A \"%s\"", lo_parm + 1);
- if( parse_line (mp, buf) != OK)
- ll_log (logptr, LLOGTMP, "problem parsing '%s'", buf);
- return ( lo_dorules(mp, mp+1) );
- case '/':
- printx ("(placing into mail file '%s')\r\n\t", lo_parm+1);
- sprintf (buf, "default - > A \"%s\"", lo_parm +1 );
- if( parse_line (mp, buf) != OK)
- ll_log (logptr, LLOGTMP, "problem parsing '%s'", buf);
- return (lo_dorules (mp, mp + 1));
- }
-
- /*
- * SECOND Attempt: user's .maildelivery file
- */
-
- if (rp_isgood (result = lo_dlvfile(dlvfile))
- || result != RP_MECH)
- return (result);
-
- /* THIRD Attempt: system delivery file */
-
- if (rp_isgood (result = lo_dlvfile(sysdlvfile))
- || result != RP_MECH)
- return (result);
-
- /* FOURTH Attempt: regular deliver to the mailbox */
-
- printx ("trying normal delivery\r\n");
- sprintf (buf, "%s/%s",
- (mldfldir == 0 || isnull(mldfldir[0])) ? "." : mldfldir,
- (mldflfil == 0 || isnull(mldflfil[0])) ? lo_pw->pw_name : mldflfil);
- return (lo_dofile (buf));
- }
- /**************** FILE DELIVERY ROUTINES *************** */
-
- LOCFUN
- lo_dofile(mboxname)
- char *mboxname;
- {
- register int retval;
-
- #ifdef DEBUG
- ll_log (logptr, LLOGBTR, "lo_dofile(%s)", mboxname);
- #endif /* DEBUG */
- printx ("\tdelivering to file '%s'", mboxname);
-
- if (rp_gval(retval = mbx_open (mboxname)) == RP_LOCK) {
- printx (", locked out\r\n");
- return (RP_LOCK);
- } else if (rp_isbad(retval)) {
- printx (", failed\r\n");
- return (retval);
- }
- retval = qu2lo_txtcpy (mbx_fd, TRUE);
- mbx_close (mboxname);
- printx (rp_isgood (retval) ? ", succeeded\r\n" : ", failed\r\n");
- return (retval);
- }
-
- LOCFUN
- qu2lo_txtcpy (ofd, tstdelim) /* copy the text of the message */
- register int ofd; /* where to send the text */
- register int tstdelim; /* should we check for message delimiters? */
- {
- register int offset;
- int len;
- int result;
- char buffer[BUFSIZ];
-
- #ifdef DEBUG
- ll_log (logptr, LLOGBTR, "qu2lo_txtcpy()");
- #endif
-
- qu_rtinit (0L);
- len = sizeof(buffer);
- while (rp_gval (result = qu_rtxt (buffer, &len)) == RP_OK) {
- if (tstdelim) { /* text may not contain a delimiter */
- /*
- * Check for occurences of the message delimiter.
- * If we find any, change the string by changing
- * the first char to a space.
- */
- if( isstr(delim1) )
- for (offset = 0;
- (offset = strindex (delim1, buffer)) >= 0;
- buffer[offset] = ' ');
-
- if( isstr(delim2) )
- for (offset = 0;
- (offset = strindex (delim2, buffer)) >= 0;
- buffer[offset] = ' ');
- }
- if (write (ofd, buffer, len) != len) {
- ll_err (logptr, LLOGTMP, "error writing out text");
- return (RP_LIO);
- }
- len = sizeof(buffer);
- }
-
- if (rp_gval (result) != RP_DONE)
- return (RP_LIO); /* didn't get it all across? */
-
- return (RP_MOK); /* got the text out */
- }
- /**************** PIPE DELIVERY ROUTINES *************** */
-
- LOCFUN
- lo_dopipe(prog)
- char *prog;
- {
- int childid; /* child does the real work */
- int ofd; /* what to write on */
- char tmpbuf[LINESIZE];
- char buffer[BUFSIZ];
- sigtype (*savepipe)();
- Pip pipdes;
- int result;
- int len;
-
- #ifdef DEBUG
- ll_log (logptr, LLOGBTR, "lo_dopipe(%s)", prog);
- #endif /* DEBUG */
-
- if( pipe(pipdes.pipcall) == NOTOK)
- return (RP_LIO);
-
- ll_close(logptr);
- switch (childid = fork ()) {
- case NOTOK:
- (void) close(pipdes.pip.prd);
- (void) close(pipdes.pip.pwrt);
- return (RP_LIO); /* problem with system */
-
- case OK:
- /* Child */
- lo_padadr();
- /* first - expand out any '$' keywords */
- expand (tmpbuf, prog, vararray);
- #ifdef DEBUG
- ll_log (logptr, LLOGBTR, "lo_dopipe() child (%s)", tmpbuf);
- #endif
- printx ("\tdelivering to pipe '%s'", tmpbuf);
- fflush (stdout);
- (void) close(0);
- dup (pipdes.pip.prd);
-
- setupenv();
-
- execle ("/bin/sh", "sh", "-c", tmpbuf, (char *)0, envp);
- ll_log( logptr, LLOGFAT, "Can't execl /bin/sh (%d)",errno);
- exit (RP_MECH);
- }
-
- /* Parent */
- /* our job is to pass on the message to the process */
- (void) close (pipdes.pip.prd);
- ofd = pipdes.pip.pwrt; /* nicer name */
- qu_rtinit(0L); /* init the message */
- savepipe = signal(SIGPIPE, onpipe);
- sigpipe = FALSE;
- len = sizeof(buffer);
- while (rp_gval(result = qu_rtxt(buffer, &len)) == RP_OK)
- {
- if( sigpipe ) /* childs had enough */
- break;
- if( write(ofd, buffer, len) != len)
- {
- if( errno != EPIPE)
- ll_err (logptr, LLOGTMP, "error on pipe %d",
- errno);
- break;
- }
- len = sizeof(buffer);
- }
- (void) close(ofd); /* finished with pipe */
- signal(SIGPIPE, savepipe); /* restore the dying signal */
- if(rp_gval(result) != RP_OK && rp_gval(result) != RP_DONE)
- return result;
- return (lo_pwait (childid, prog)); /* .... and wait */
- }
-
- LOCFUN
- lo_pwait (procid, prog) /* wait for child to complete */
- int procid; /* id of child process */
- char *prog;
- {
- int status;
-
- #ifdef DEBUG
- ll_log (logptr, LLOGBTR, "lo_pwait ()");
- #endif
-
- if (setjmp (timerest) == 0)
- { /* alarm is in case user's pgm hangs */
- flgtrest = TRUE;
- /*NOSTRICT*/
- s_alarm ((unsigned) (qu_msglen / 20) + 300);
- errno = 0;
- status = pgmwait (procid);
- s_alarm (0);
- if (status == NOTOK) {
- /* system killed the process */
- ll_err (logptr, LLOGTMP, "bad return: (%s) %s [wait=NOTOK]",
- lo_pw->pw_name, prog);
- return (RP_LIO);
- }
- ll_log (logptr, LLOGBTR, "(%s) %s [%s]",
- lo_pw->pw_name, prog, rp_valstr (status));
- if( status == 0) /* A-OK */
- {
- printx (", succeeded\r\n");
- return (RP_MOK);
- }
- else if(status == 1) /* command not found - ECB */
- {
- printx (", failed (PATH)\r\n");
- return (RP_MECH);
- }
- else if( rp_gbval(status) == RP_BNO) /* permanent error */
- {
- printx (", failed (perm)\r\n");
- return (RP_NO);
- }
- else /* temp error */
- {
- printx (", failed (temp)\r\n");
- return (RP_MECH);
- }
- /* NOTREACHED */
- }
- else
- {
- flgtrest = FALSE;
- printx (", user program taking too long");
- ll_log (logptr, LLOGGEN, "user program taking too long - killing");
- #ifndef V4_2BSD
- kill (procid, SIGKILL); /* we're superuser, so always works */
- #else /* V4_2BSD */
- killpg (procid, SIGKILL); /* we're superuser, so always works*/
- #endif /* V4_2BSD */
- return (RP_TIME);
- }
- }
-
- /* ensure that all addresses can be passed to shell */
- lo_padadr()
- {
- static done_pad = 0;
- register int i;
- register char *c1, *c2, *p;
- char tmp[2 * LINESIZE];
-
- if (done_pad)
- return;
-
- for(i=0; vararray[i] != 0; i += 2)
- {
- (void) strcpy(tmp,vararray[i+1]);
-
- for(c1=tmp,c2=vararray[i+1]; *c1 != '\0'; c1++)
- {
- for(p=padchar; *p != '\0'; p++)
- {
- if (*p == *c1)
- {
- *c2++ = '\\';
- break;
- }
- }
-
- *c2++ = *c1;
- }
- *c2 = '\0';
- }
- }
-
- /******** (mbx_) STANDARD DELIVERY TO MAILBOX STYLE FILE *********** */
-
- mbx_open (file) /* stuff into mailbox */
- char *file;
- {
- struct stat mbxstat;
- register int count;
- short retval;
- int mbxmade; /* Infinite loop preventer */
-
- #ifdef DEBUG
- ll_log (logptr, LLOGBTR, "mbx_open (%s)", file);
- #endif
- mbxmade = mbx_wasclear = FALSE;
- reopen:
- if ((mbx_fd = lk_open (file, 2, (char *) 0, (char *) 0, 10)) < 0)
- {
- switch (errno) {
- #ifdef EWOULDBLOCK
- case EWOULDBLOCK:
- #endif /* EWOULDBLOCK */
- case ETXTBSY:
- printx (", mail file is locked");
- return (RP_LOCK);
-
- case ENOENT: /* doesn't exist */
- if (!mbxmade && rp_isgood (mbx_create (file))) {
- printx (", mail file created");
- mbxmade = mbx_wasclear = TRUE;
- goto reopen;
- }
- /* DROP THROUGH */
- default:
- ll_err (logptr, LLOGTMP, "can't open mailbox '%s'",
- file);
- return (RP_LIO);
- }
- }
- else
- {
- if (fstat (mbx_fd, &mbxstat) < 0)
- {
- ll_err (logptr, LLOGTMP, "can't fstat %s", file);
- return (RP_LIO);
- }
- mbx_wasclear = (st_gsize (&mbxstat) == 0L);
- }
-
- if (!mbx_wasclear && rp_isbad (retval = mbx_chkdelim ()))
- return (retval); /* mbox has bad terminator */
-
- count = strlen (delim1); /* write prefatory separator */
- if (write (mbx_fd, delim1, count) != count)
- {
- ll_err (logptr, LLOGTMP, "error writing delim1");
- return (RP_LIO);
- }
-
- return (RP_OK);
- }
- /**/
-
- LOCFUN
- mbx_create (mboxname) /* create receiver's mailbox file */
- char *mboxname;
- {
- #ifdef DEBUG
- ll_log (logptr, LLOGBTR, "mbx_create (%s)", mboxname);
- #endif
-
- if ((mbx_fd = creat (mboxname, sentprotect)) < 0)
- {
- ll_err (logptr, LLOGFAT, "can't create mailbox '%s'",
- mboxname);
- return (RP_LIO);
- }
- (void) close (mbx_fd); /* unix create() forces wrong modes */
-
- return (RP_OK);
- }
-
- LOCFUN
- mbx_close (file) /* done with mailbox */
- char *file;
- {
- short count;
-
- #ifdef DEBUG
- ll_log (logptr, LLOGBTR, "mbx_close ()");
- #endif
- if (mbx_fd < 0)
- {
- #ifdef DEBUG
- ll_log (logptr, LLOGFTR, "not open");
- #endif
- return;
- }
-
- count = strlen (delim2);
- if (write (mbx_fd, delim2, count) != count)
- { /* couldn't put ending delimiter on */
- ll_err (logptr, LLOGTMP, "error writing delim2");
- }
- lk_close (mbx_fd, file, (char *) 0, (char *) 0);
- mbx_fd = -1;
- }
- /**/
-
- LOCFUN
- mbx_chkdelim () /* last msg delimited properly? */
- { /* check ending delimiter of last msg */
- int count;
- char ldelim[LINESIZE];
- struct stat statb;
-
- #ifdef DEBUG
- ll_log (logptr, LLOGBTR, "mbx_chkdelim ()");
- #endif
-
- count = strlen (delim2);
-
- if (lseek (mbx_fd, (long)(-count), 2) == (long) NOTOK ||
- read (mbx_fd, ldelim, count) != count) {
- printx(", mailbox is missing delimiter");
- if (fstat(mbx_fd, &statb) == 0 && statb.st_size < count) {
- lseek(mbx_fd, 0L, 2);
- goto patch;
- }
- printx(", mailbox lseek/read errors");
- return (RP_LIO);
- }
-
- if (count == 0)
- return (RP_OK);
- if (!initstr (delim2, ldelim, count))
- { /* previous didn't end cleanly. patch */
- ll_err (logptr, LLOGTMP, "bad delim; patching");
- patch: printx("\n\tpatching in missing delimiter");
-
- if ((write (mbx_fd, "\n", 1) != 1) ||
- (write (mbx_fd, delim2, count) != count))
- { /* write separator */
- ll_err (logptr, LLOGTMP, "unable to patch");
- return (RP_LIO);
- }
- }
- return (RP_OK);
- }
- /******************* MAILDELIVERY HANDLING ROUTINES ***************/
-
- /*
- * Given a maildelivery format file, this routine parses the
- * file into an array - then calls dorules to follow the actions.
- * The file is either personal
- * e.g. .maildelvery
- * or else system wide
- * i.e. /usr/lib/maildlvry
- */
-
- lo_dlvfile (dlv_file)
- char *dlv_file; /* the file to scan */
- {
- register FILE *fp;
- struct stat sb;
- Mdlvry thefile[MAXLINES]; /* the representation of the md file */
- register Mdlvry *mptr, *maxptr; /* some handy pointers */
- char dlvline[LINESIZE];
- int len;
-
- #ifdef DEBUG
- ll_log (logptr, LLOGBTR, "lo_dlvfile(%s)", seenull(dlv_file));
- #endif /* DEBUG */
-
- if ((!isstr(dlv_file)) || (fp = fopen(dlv_file, "r")) == NULL)
- return (RP_MECH);
-
- /* Security Check!
- *
- * The file must owned by the person we are delivering to
- * or the superuser. In addition, the file must not have
- * write permission to anyone accept the owner. (DPK)
- * In the case of system wide file, this is constrained to
- * be root generally. (JPO)
- */
-
- if (fstat (fileno(fp), &sb) < 0
- || (sb.st_uid != lo_pw->pw_uid && sb.st_uid != 0)
- || sb.st_mode & 022) {
- printx("ownership problems on '%s'\n", dlv_file);
- ll_log (logptr, LLOGBTR, "ownership problems on '%s'",
- dlv_file);
- fclose(fp);
- return (RP_MECH);
- }
-
- for (mptr = thefile;
- (len = gcread(fp, dlvline, LINESIZE, "\n\377")) > 0
- && mptr < &thefile[MAXLINES];)
- {
- if( dlvline[0] == '\n' || dlvline[0] == '#' )
- continue; /* skip this line */
-
- dlvline[len - 1] = '\0'; /* zap the lf */
-
- if( parse_line(mptr, dlvline) == OK)
- mptr ++;
- }
- if ( mptr >= &thefile[MAXLINES] )
- ll_log (logptr, LLOGFST, "more than %d lines in %s (%s)",
- MAXLINES, dlv_file, lo_pw->pw_name);
-
- maxptr = mptr;
- fclose (fp); /* OK, file finished, take a deep breath and ... */
- return lo_dorules(thefile, maxptr);
- }
-
- /*
- * apply the given rules. mptr is the begining of an array of
- * rules, mpmax is the last rule in the array + 1.
- */
-
- lo_dorules(mptr, mpmax) /* apply the maildelivwery rules */
- Mdlvry *mptr, *mpmax;
- {
- int doneparse = FALSE; /* a couple of bools */
- int delivered = FALSE;
- int retval;
- /*
- * Now comes the bit where we try and be fearfully clever.
- * We proceed down the array of md lines, whistling nochalantly,
- * until we hit a situation where parsing must take place.
- * At this point (with a sheepish grin) we then go and dig into
- * the message and see what we can find, and then continue on as
- * if nothing had happened.
- */
-
- for(; mptr < mpmax; mptr ++)
- {
- if( delivered && mptr->m_ar == M_CONDACC)
- continue; /* this line can be ignored */
- if( mptr->m_parse && !doneparse) /* arggh caught out! */
- {
- if(rp_isgood( dotheparse(mptr, mpmax)))
- doneparse = TRUE;
- else return RP_NO;
- }
- if(! mptr->m_special ) /* this is a real header */
- {
- if( !mptr->m_hit)
- continue; /* but no hit */
- #ifdef DEBUG
- ll_log (logptr, LLOGFTR, "hit with %s (%s)",
- mptr->m_pattern, mptr->m_header);
- #endif /* DEBUG */
- /* else we drop through to beyond the switch */
- } /* beware the dangling else !! */
- else /* do the switch */
- {
- /* Run through the special case headers, break if hit, continue if miss */
- switch( mptr->m_hdrtype)
- {
- case M_DEFAULT:
- if( ! delivered ) /* this applys */
- break;
- continue;
- case M_ADDRESS:
- if( strindex(mptr->m_pattern, lo_adr) >= 0)
- break;
- continue;
- case M_TRUE: /* always true */
- break;
- case M_SENDER:
- if( strindex(mptr->m_pattern, lo_sender) >= 0)
- break;
- continue;
- default: /* what else can we do ? */
- continue;
- }
- }
- /* OK, do the action */
- retval = lo_doaction(mptr);
-
- switch( mptr->m_ar) /* now how did it go ? */
- {
- case M_CONDACC:
- case M_ACCEPT:
- if( rp_isgood(retval)) /* delivered */
- delivered = TRUE;
- else if(rp_gval(retval) != RP_NO)
- return RP_AGN; /* went bad (temp) */
- break;
- case M_REJECT:
- continue;
- }
- }
- return(delivered ? RP_MOK : RP_MECH);
- }
-
- parse_line(mptr, line) /* dump the line into the Mdlvry struct */
- Mdlvry *mptr;
- char *line;
- {
- char *argv[15]; /* the argv array */
- char opts[LINESIZE]; /* temp space for gathering opts */
- int argc;
- int type;
- int i;
- Lookup *lp;
-
- #ifdef DEBUG
- ll_log (logptr, LLOGBTR, "parse_line(%s)", line);
- #endif /* DEBUG */
-
- argc = sstr2arg(line, 15, argv, " \t,"); /* split it */
- if( argc < 4 ) /* not good enough! */
- return NOTOK;
- if( (type = lookup(argv[0], spec_hdrs)) == -1 ) /* not a special ?*/
- {
- mptr->m_parse = TRUE;
- mptr->m_special = FALSE;
- mptr->m_header = strdup(argv[0]);
- mptr->m_pattern = strdup(argv[1]);
- #ifdef DEBUG
- ll_log (logptr, LLOGFTR, "header='%s' pat='%s'",
- mptr->m_header, mptr->m_pattern);
- #endif /* DEBUG */
- }
- else /* Oh, it is a special */
- {
- mptr->m_special = TRUE;
- mptr->m_parse = FALSE;
- mptr->m_hdrtype = type;
- mptr->m_header = NULL;
- mptr->m_pattern = strdup(argv[1]);
- #ifdef DEBUG
- ll_log (logptr, LLOGFTR, "special pat='%s'", mptr->m_pattern);
- #endif /* DEBUG */
- }
- switch( argv[3][0] ) /* only a,A & ? - anything else == R */
- {
- case 'A':
- case 'a':
- mptr->m_ar = M_ACCEPT;
- break;
- case '?':
- mptr->m_ar = M_CONDACC;
- break;
- default:
- case 'r':
- case 'R':
- mptr->m_ar = M_REJECT;
- break;
- }
- #ifdef DEBUG
- ll_log (logptr, LLOGFTR, "action=%o", mptr->m_ar);
- #endif /* DEBUG */
- if( (type = lookup(argv[2], actions)) == -1)
- ll_log(logptr, LLOGFAT, "Unknown action to perform '%s'\n",
- argv[2]); /* a `never happens case' */
- else mptr->m_action = type;
- #ifdef DEBUG
- ll_log (logptr, LLOGFTR, "action=%o", mptr->m_action);
- #endif /* DEBUG */
- switch (mptr->m_action )
- {
- case M_FILE:
- mptr->m_options = strdup(argv[4]);
- break;
- case M_DESTROY:
- break;
- case M_PIPE: /* gather together the argv's */
- opts[0] = '\0';
- for( i = 4; i < argc; i++)
- {
- strcat(opts, argv[i]);
- if( i != argc -1 )
- strcat(opts, " ");
- }
- mptr->m_dollar = 0;
- mptr->m_options = strdup(opts);
- for(lp = dolfields; lp->l_key != NULL; lp++)
- if( strindex(lp->l_key, opts) >= 0)
- {
- mptr->m_parse = TRUE;
- mptr->m_dollar |= lp->l_val;
- }
- break;
- default:
- break;
- }
- mptr->m_hit = 0;
- #ifdef DEBUG
- ll_log (logptr, LLOGFTR, "dol=%o parse=%o opts='%s'",
- mptr->m_dollar, mptr->m_parse, mptr->m_options);
- #endif /* DEBUG */
- return OK;
- }
- lo_doaction(mp)
- Mdlvry *mp;
- {
- # ifdef DEBUG
- ll_log (logptr, LLOGBTR, "lo_doaction");
- #endif /* DEBUG */
-
- switch( mp->m_action )
- {
- case M_DESTROY: /* /dev/null it */
- return (RP_MOK);
-
- /* pipe has gone away */
- case M_PIPE:
- return lo_dopipe(mp->m_options);
- case M_FILE:
- return lo_dofile(mp->m_options);
- default:
- ll_log( logptr, LLOGFAT, "unidentified action type %o",
- mp->m_action);
- return RP_NO;
- }
- /* NOTREACHED */
- }
- /**************** PARSING DELIVERY ROUTINES *************** */
-
- /*
- * the routine that actually parses the message and sets up hit/miss
- * bits in the md struct.
- */
-
- dotheparse(mpbase, mpmax)
- Mdlvry *mpbase, *mpmax;
- {
- char line[LINESIZE];
- char name[LINESIZE], contents[LINESIZE];
- Mdlvry *mp;
- int len;
- int gotrepl = 0;
-
- # ifdef DEBUG
- ll_log (logptr, LLOGBTR, "dotheparse()");
- #endif /* DEBUG */
- /* start reading header */
- qu_rtinit(0L);
-
- while((len = hdr_line(line, LINESIZE)) > 0)
- {
- line[len] = '\0';
- switch(hdr_parse(line, name, contents))
- {
- case HDR_NAM:
- continue; /* to avoid break */
-
- case HDR_EOH:
- break; /* break out of loop below */
-
- case HDR_NEW:
- case HDR_MOR:
- for(mp = mpbase; mp < mpmax; mp++)
- {
- if( !mp->m_hit && lexequ(mp->m_header, name) &&
- strindex(mp->m_pattern, contents) >= 0)
- {
- mp->m_hit = TRUE;
- #ifdef DEBUG
- ll_log (logptr, LLOGFTR, "hit in parse '%s' & '%s'",
- contents, mp->m_pattern);
- #endif /* DEBUG */
- }
- if(( mp->m_dollar & 1))
- if(! gotrepl && lexequ(name, "from"))
- (void) strcpy(lo_replyto, contents);
- else if(lexequ(name, "reply-to"))
- {
- (void) strcpy(lo_replyto, contents);
- gotrepl = TRUE;
- }
- }
- continue;
- } /* end switch */
- break;
- }
-
- if (len <= 0)
- return RP_NO;
- return RP_OK;
- }
-
- /* basic processing of incoming header lines */
- LOCFUN
- hdr_line(buf, len)
- char *buf;
- int len;
- {
- register int count;
- static char hdr_buf[LINESIZE]; /* buffer */
- static int buf_cnt = 0; /* chars in buf */
- static char *buf_ptr;
- register char *hp;
- register char *bp;
-
- count = len;
- hp = buf_ptr;
- bp = buf;
- while (count > 0)
- {
- if (buf_cnt == 0)
- {
- buf_cnt = sizeof(hdr_buf);
- if (qu_rtxt(hdr_buf,&buf_cnt) != RP_OK)
- buf_cnt = 0; /* break below */
- hp = hdr_buf;
- }
-
- /* any more chars? */
- if (buf_cnt <= 0)
- break;
-
- /* bugfix from howard */
- buf_cnt--;
- count--;
-
- if ((*bp++ = *hp++) == '\n')
- break;
- }
-
- buf_ptr = hp;
-
- #ifdef DEBUG
- ll_log(logptr, LLOGFTR, "hdr_line (%*s)", len-count, (len-count)?buf:"");
- #endif
-
- return(len - count);
- }
-
- LOCFUN
- hdr_parse (src, name, contents) /* parse one header line */
- register char *src; /* a line of header text */
- char *name, /* where to put field's name */
- *contents; /* where to put field's contents */
- {
- extern char *compress ();
- char linetype;
- register char *dest;
-
- #ifdef DEBUG
- ll_log (logptr, LLOGBTR, "hdr_parse(%s)", src);
- #endif
-
- if (isspace (*src))
- { /* continuation text */
- #ifdef DEBUG
- ll_log (logptr, LLOGFTR, "cmpnt more");
- #endif
- if (*src == '\n')
- return (HDR_EOH);
- linetype = HDR_MOR;
- }
- else
- { /* copy the name */
- linetype = HDR_NEW;
- for (dest = name; *dest = *src++; dest++)
- {
- if (*dest == ':')
- break; /* end of the name */
- if (*dest == '\n')
- { /* oops, end of the line */
- *dest = '\0';
- return (HDR_NAM);
- }
- }
- *dest = '\0';
- compress (name, name); /* strip extra & trailing spaces */
- #ifdef DEBUG
- ll_log (logptr, LLOGFTR, "cmpnt name '%s'", name);
- #endif
- }
-
- for (dest = contents; isspace (*src); )
- if (*src++ == '\n') /* skip leading white space */
- { /* unfulfilled promise, no contents */
- *dest = '\0';
- return ((linetype == HDR_MOR) ? HDR_EOH : linetype);
- } /* hack to fix up illegal spaces */
-
- while ((*dest = *src) != '\n' && *src != 0)
- src++, dest++; /* copy contents and then, backup */
- while (isspace (*--dest)); /* to eliminate trailing spaces */
- *++dest = '\0';
-
- return (linetype);
- }
- /*************** (misc) MISCELLANEOUS ROUTINES ******************** */
-
- /*
- * Dig into table for a match - return associated value else -1
- * table ends when key == 0;
- * (JPO)
- */
-
- LOCFUN
- lookup( str, table )
- char *str;
- Lookup table[];
- {
- register Lookup *p;
-
- for(p = table; p -> l_key ; p++)
- {
- /*
- * match with prefix, this allows "addr" to match "address"
- */
- if( prefix(p -> l_key, str) )
- return (p -> l_val);
- }
- return (-1);
- }
-
- /*
- * setup the environment for the process to run in. This includes :-
- * Environment variables
- * file descriptors - close all but fd0
- * process groups
- * controlling ttys.
- * umask
- */
-
- LOCFUN setupenv()
- {
- int fd;
- static char homestr[64]; /* environment $HOME param */
- static char shellstr[64]; /* environment $SHELL param */
- static char userstr[64]; /* environment $USER param */
-
- #ifdef DEBUG
- ll_log (logptr, LLOGBTR, "setupenv()");
- #endif /* DEBUG */
- for (fd = 1; fd < numfds; fd++)
- (void) close (fd);
- fd = open ("/dev/null", 1); /* stdout */
- dup (fd); /* stderr */
-
- umask(077); /* Restrictive umask */
-
- #ifdef TIOCNOTTY
- if (setjmp (timerest) == 0)
- {
- flgtrest = TRUE;
- s_alarm(15); /* should be enough */
- if( (fd = open("/dev/tty", 2)) != NOTOK) {
- (void) ioctl(fd, TIOCNOTTY, (char *)0);
- (void) close(fd);
- }
- s_alarm(0);
- }
- else
- {
- flgtrest = FALSE;
- ll_log (logptr, LLOGGEN, "TIOCNOTTY not available");
- }
- #endif /* TIOCNOTTY */
- #ifdef V4_2BSD
- setpgrp (0, getpid());
- #endif
- sprintf (homestr, "HOME=%s", lo_pw->pw_dir);
- sprintf (shellstr, "SHELL=%s",
- isstr(lo_pw->pw_shell) ? lo_pw->pw_shell : "/bin/sh");
- sprintf (userstr, "USER=%s", lo_pw->pw_name);
- envp[0] = homestr;
- envp[1] = shellstr;
- envp[2] = userstr;
- }
-
- sigtype
- onpipe()
- {
- signal(SIGPIPE, onpipe);
- sigpipe = TRUE;
- }
-